package de.bht.cge.flightsim.treeplanter;

import java.util.ArrayList;
import java.util.List;

import de.bht.cge.flightsim.game.Tree;
import de.bht.jvr.core.GroupNode;
import de.bht.jvr.core.SceneNode;
import de.bht.jvr.core.ShapeNode;
import de.bht.jvr.core.Transform;
import de.bht.jvr.core.TriangleMesh;
import de.bht.jvr.math.Matrix4;
import de.bht.jvr.math.Vector4;

public class TreePlanter
{
    public static SceneNode makeVegetation(ShapeNode terrainShape, Transform terrainWorldTrans, List<Tree> trees, float min, float max)
    {
        TreePlanter planter = new TreePlanter(terrainShape, terrainWorldTrans, trees, min, max);
        return planter.getVegetation();
    }    
    
    private SceneNode vegetation = null;
    public TreePlanter(ShapeNode terrainShape, Transform terrainWorldTrans, List<Tree> trees, float minHeight, float maxHeight)
    {
        // extract geometry
        TriangleMesh geo = (TriangleMesh)terrainShape.getGeometry();
        
        // extract vertices and transform to world space
        List<Vector4> vertices = new ArrayList<Vector4>(); 
        Matrix4 trans = terrainWorldTrans.getMatrix();
        for(int i=0; i<geo.getVerticesCount(); i++)
        {
            Vector4 vertex = geo.getVertex(i);
            vertex = trans.mul(vertex).homogenize();
            vertices.add(vertex);
        }
        
        // remove identical vertices
        List<Vector4> cleanVertices = new ArrayList<Vector4>();
        for(Vector4 vertex: vertices)
        {
            boolean found = false;
            for(Vector4 v: cleanVertices)
            {
                if(v.equals(vertex))
                {
                    found = true;
                    break;
                }
            }
            
            if(!found)
            {
                cleanVertices.add(vertex);
            }
        }
        
        // plant the trees
        GroupNode vegetation = new GroupNode();
        GroupNode vegetationCluster = new GroupNode();
        int maxTreesInCluster = 128;
        int treesInCluster = 0;
        for(Vector4 vertex: cleanVertices)
        {
            if(vertex.y() > minHeight && vertex.y() < maxHeight && random(1)==1)
            {
                GroupNode treeRoot = new GroupNode(); // create a group node for the tree
                treeRoot.addChildNode(trees.get(random(trees.size()-1))); // select a random tree and append it to the group node
                treeRoot.setTransform(Transform.translate(vertex.xyz()).mul(Transform.rotateYDeg(random(360)))); // transform the group node to the vertex position                
                vegetationCluster.addChildNode(treeRoot); // append the group node to the vegetation group
                treesInCluster++;
                
                if(treesInCluster == maxTreesInCluster)
                {
                    vegetation.addChildNode(vegetationCluster);
                    vegetationCluster = new GroupNode();
                    treesInCluster = 0;
                }
            }
        }
        
        // if the last cluster is not full
        if(treesInCluster > 0)
        {
            vegetation.addChildNode(vegetationCluster);
        }
        
        this.vegetation = vegetation;
    }
    
    private static int random(int max)
    {
        return (int)(Math.random() * (max+1));
    }
    
    public SceneNode getVegetation()
    {
        return this.vegetation;
    }
}
